package com.carrental.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carrental.auth.dto.LoginDTO;
import com.carrental.auth.dto.RegisterDTO;
import com.carrental.auth.entity.User;
import com.carrental.auth.mapper.UserMapper;
import com.carrental.auth.service.UserService;
import com.carrental.auth.util.JwtTokenUtil;
import com.carrental.auth.vo.LoginVO;
import com.carrental.auth.vo.UserInfoVO;
import com.carrental.common.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;

/**
 * 用户服务实现类
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
    
    private final JwtTokenUtil jwtTokenUtil;
    private final RedisTemplate<String, Object> redisTemplate;
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    /**
     * 用户登录
     *
     * @param loginDTO 登录参数
     * @return 登录结果
     */
    @Override
    public LoginVO login(LoginDTO loginDTO) {
        log.info("用户登录请求: username={}", loginDTO.getUsername());
        
        try {
            // 根据用户名查询用户
            User user = getOne(new LambdaQueryWrapper<User>()
                    .eq(User::getUsername, loginDTO.getUsername())
                    .eq(User::getDeleted, 0));
            String testPassword = testPassword("admin");
            // 用户不存在
            if (user == null) {
                log.warn("登录失败: 用户不存在, username={}", loginDTO.getUsername());
                throw new BusinessException("用户名或密码错误");
            }
            
            // 用户被禁用
            if (user.getStatus() == 0) {
                log.warn("登录失败: 账号已被禁用, username={}, userId={}", loginDTO.getUsername(), user.getId());
                throw new BusinessException("账号已被禁用");
            }

            // 更新登录信息
            user.setLastLoginTime(LocalDateTime.now());
            updateById(user);
            log.debug("更新用户最后登录时间: userId={}, lastLoginTime={}", user.getId(), user.getLastLoginTime());

            // 生成token
            String token = jwtTokenUtil.generateToken(user.getId(), user.getUsername());
            log.debug("生成用户token: userId={}, token={}", user.getId(), token);

            // 将token存入Redis，设置过期时间
            redisTemplate.opsForValue().set("token:" + token, user.getId(), jwtTokenUtil.getExpiration(), TimeUnit.SECONDS);
            log.debug("将token存入Redis: userId={}, expiration={}秒", user.getId(), jwtTokenUtil.getExpiration());

            // 获取用户信息
            UserInfoVO userInfo = getUserInfo(user.getId());

            log.info("用户登录成功: username={}, userId={}", loginDTO.getUsername(), user.getId());
            // 返回登录结果
            return new LoginVO(token, jwtTokenUtil.getExpiration(), userInfo);
        } catch (BusinessException e) {
            // 业务异常直接抛出
            throw e;
        } catch (Exception e) {
            // 记录未预期的异常
            log.error("登录过程发生异常: username={}", loginDTO.getUsername(), e);
            throw new BusinessException("登录失败，系统异常");
        }
    }

    /**
     * 用户注册
     *
     * @param registerDTO 注册参数
     * @return 注册结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean register(RegisterDTO registerDTO) {
        log.info("用户注册请求: username={}, mobile={}", registerDTO.getUsername(), registerDTO.getMobile());
        
        try {
            // 验证密码是否一致
            if (!Objects.equals(registerDTO.getPassword(), registerDTO.getConfirmPassword())) {
                log.warn("注册失败: 两次密码不一致, username={}", registerDTO.getUsername());
                throw new BusinessException("两次密码不一致");
            }

            // 验证用户名是否已存在
            long count = count(new LambdaQueryWrapper<User>()
                    .eq(User::getUsername, registerDTO.getUsername())
                    .eq(User::getDeleted, 0));
            if (count > 0) {
                log.warn("注册失败: 用户名已存在, username={}", registerDTO.getUsername());
                throw new BusinessException("用户名已存在");
            }

            // 验证手机号是否已存在
            count = count(new LambdaQueryWrapper<User>()
                    .eq(User::getMobile, registerDTO.getMobile())
                    .eq(User::getDeleted, 0));
            if (count > 0) {
                log.warn("注册失败: 手机号已存在, mobile={}", registerDTO.getMobile());
                throw new BusinessException("手机号已存在");
            }

            // 创建用户
            User user = new User();
            user.setUsername(registerDTO.getUsername());
            user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
            user.setRealName(registerDTO.getRealName());
            user.setMobile(registerDTO.getMobile());
            user.setEmail(registerDTO.getEmail());
            user.setUserType(registerDTO.getUserType());
            user.setStatus(1);
            user.setCreateTime(LocalDateTime.now());
            user.setUpdateTime(LocalDateTime.now());
            user.setDeleted(0);

            boolean result = save(user);
            if (result) {
                log.info("用户注册成功: username={}, userId={}", registerDTO.getUsername(), user.getId());
            } else {
                log.warn("用户注册失败: username={}", registerDTO.getUsername());
            }
            return result;
        } catch (BusinessException e) {
            // 业务异常直接抛出
            throw e;
        } catch (Exception e) {
            // 记录未预期的异常
            log.error("注册过程发生异常: username={}", registerDTO.getUsername(), e);
            throw new BusinessException("注册失败，系统异常");
        }
    }

    /**
     * 获取用户信息
     *
     * @param userId 用户ID
     * @return 用户信息
     */
    @Override
    public UserInfoVO getUserInfo(Long userId) {
        log.debug("获取用户信息: userId={}", userId);
        
        try {
            // 查询用户
            User user = getById(userId);
            if (user == null) {
                log.warn("获取用户信息失败: 用户不存在, userId={}", userId);
                throw new BusinessException("用户不存在");
            }

            // 查询角色和权限
            List<String> roles = baseMapper.selectRoleCodesByUserId(userId);
            List<String> permissions = baseMapper.selectPermissionCodesByUserId(userId);
            log.debug("获取用户角色和权限: userId={}, roles={}, permissionsCount={}", userId, roles, permissions.size());

            // 封装用户信息
            UserInfoVO userInfoVO = new UserInfoVO();
            userInfoVO.setId(user.getId());
            userInfoVO.setUsername(user.getUsername());
            userInfoVO.setRealName(user.getRealName());
            userInfoVO.setMobile(user.getMobile());
            userInfoVO.setEmail(user.getEmail());
            userInfoVO.setAvatar(user.getAvatar());
            userInfoVO.setGender(user.getGender());
            userInfoVO.setUserType(user.getUserType());
            userInfoVO.setRoles(roles);
            userInfoVO.setPermissions(permissions);

            log.debug("获取用户信息成功: userId={}", userId);
            return userInfoVO;
        } catch (BusinessException e) {
            // 业务异常直接抛出
            throw e;
        } catch (Exception e) {
            // 记录未预期的异常
            log.error("获取用户信息过程发生异常: userId={}", userId, e);
            throw new BusinessException("获取用户信息失败，系统异常");
        }
    }

    /**
     * 刷新token
     *
     * @param token 旧token
     * @return 新token
     */
    @Override
    public String refreshToken(String token) {
        log.debug("刷新token请求");
        
        try {
            // 验证token
            if (!jwtTokenUtil.validateToken(token)) {
                log.warn("刷新token失败: token无效");
                return null;
            }

            // 从Redis中获取用户ID
            Object userId = redisTemplate.opsForValue().get("token:" + token);
            if (userId == null) {
                log.warn("刷新token失败: Redis中不存在token");
                return null;
            }

            // 删除旧token
            redisTemplate.delete("token:" + token);
            log.debug("从Redis中删除旧token");

            // 查询用户
            User user = getById(Long.valueOf(userId.toString()));
            if (user == null) {
                log.warn("刷新token失败: 用户不存在, userId={}", userId);
                return null;
            }

            // 生成新token
            String newToken = jwtTokenUtil.generateToken(user.getId(), user.getUsername());
            log.debug("生成新token: userId={}", user.getId());

            // 将新token存入Redis
            redisTemplate.opsForValue().set("token:" + newToken, user.getId(), jwtTokenUtil.getExpiration(), TimeUnit.SECONDS);
            log.debug("将新token存入Redis: userId={}", user.getId());

            log.info("刷新token成功: userId={}", user.getId());
            return newToken;
        } catch (Exception e) {
            log.error("刷新token过程发生异常", e);
            return null;
        }
    }

    /**
     * 退出登录
     *
     * @param token 令牌
     * @return 是否成功
     */
    @Override
    public boolean logout(String token) {
        log.info("退出登录请求");
        
        try {
            // 从Redis中删除token
            boolean result = Boolean.TRUE.equals(redisTemplate.delete("token:" + token));
            if (result) {
                log.info("退出登录成功: token已从Redis中删除");
            } else {
                log.warn("退出登录失败: Redis中不存在token");
            }
            return result;
        } catch (Exception e) {
            log.error("退出登录过程发生异常", e);
            return false;
        }
    }

    /**
     * 从token中获取用户ID
     *
     * @param token token
     * @return 用户ID
     */
    @Override
    public Long getUserIdFromToken(String token) {
        log.debug("从token中获取用户ID");
        
        try {
            // 从Redis中获取用户ID
            Object userId = redisTemplate.opsForValue().get("token:" + token);
            if (userId != null) {
                log.debug("从Redis中获取到用户ID: userId={}", userId);
                return Long.valueOf(userId.toString());
            }
            
            // 从token中解析用户ID
            Long id = jwtTokenUtil.getUserIdFromToken(token);
            log.debug("从token中解析用户ID: userId={}", id);
            return id;
        } catch (Exception e) {
            log.error("从token中获取用户ID过程发生异常", e);
            return null;
        }
    }

    @Override
    public List<String> getRolesByUserId(Long userId) {
        log.debug("获取用户角色: userId={}", userId);
        try {
            return baseMapper.selectRoleCodesByUserId(userId);
        } catch (Exception e) {
            log.error("获取用户角色失败: userId={}", e.getMessage());
            return Collections.emptyList();
        }
    }

    @Override
    public String testPassword(String password) {
        return passwordEncoder.encode(password);
    }
}